﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    /// <summary>
    /// C#8.0和.NETCore 3.0高级编程
    /// </summary>
    public class C80AndNETCore30
    {
        #region P4-5 448 VSCode及C#扩展
        //搜索VS Code C# 扩展
        //REST Client扩展测试HTTP请求
        #endregion

        #region P308 异步运行任务，继续执行另一项任务
        static string CallA(int num)
        {
            Console.WriteLine("begin call a");
            Thread.Sleep(num);
            Console.WriteLine("finish call a");
            return "a";
        }
        static string CallB(int num)
        {
            Console.WriteLine("begin call b");
            Thread.Sleep(num);
            Console.WriteLine("finish call b");
            return "b";
        }
        static void TestCall()
        {
            var call = Task.Factory.StartNew(() => CallA(5000)).ContinueWith(t => CallB(10)).Result;
        }
        #endregion

        #region P311-312 同步访问共享资源——从多个线程访问资源
        static Random r = new Random();
        static string Message1;

        static void MethodA1()
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(r.Next(1000));
                Message1 += "A";
                Console.Write(".");
            }
        }
        static void MethodB1()
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(r.Next(1000));
                Message1 += "B";
                Console.Write(".");
            }
        }
        static void TestMethod1()
        {
            Stopwatch watch = Stopwatch.StartNew();
            Task a = Task.Factory.StartNew(MethodA1);
            Task b = Task.Factory.StartNew(MethodB1);

            Task.WaitAll(new Task[] { a, b });
            Console.WriteLine($"Message1={Message1}");
            Console.WriteLine($"{watch.ElapsedMilliseconds:#,##0}");
        }
        #endregion

        #region P311-312 同步访问共享资源——对应资源互斥锁
        static object obj = new object();
        static string Message2;

        static void MethodA2()
        {
            lock (obj)
            {

                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(r.Next(2000));
                    Message2 += "A";
                    Console.Write(".");
                }
            }
        }
        static void MethodB2()
        {
            lock (obj)
            {
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(r.Next(2000));
                    Message2 += "B";
                    Console.Write(".");
                }
            }
        }
        static void TestMethod2()
        {
            Stopwatch watch = Stopwatch.StartNew();
            Task a = Task.Factory.StartNew(MethodA2);
            Task b = Task.Factory.StartNew(MethodB2);

            Task.WaitAll(new Task[] { a, b });
            Console.WriteLine($"Message2={Message2}");
            Console.WriteLine($"{watch.ElapsedMilliseconds:#,##0}");
        }
        #endregion

        #region P311-312 同步访问共享资源——理解lock语句并避免死锁
        /*
         * 死锁往往发生在有两个或多个共享资源时，事件发生的顺序如下：
         * 线程X锁定conch A，线程Y锁定conch B。
         * 线程X试图锁定conch B，但被阻塞，因为线程Y已经锁定了conch B。
         * 线程Y试图锁定conch A，但被阻塞，因为线程X已经锁定了conch A。
         */
        static object conch = new object();
        static string Message3;

        static void MethodA3()
        {
            try
            {
                Monitor.TryEnter(conch, TimeSpan.FromSeconds(5));
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(r.Next(1000));
                    Message3 += "A";
                    Console.Write(".");
                }
            }
            finally
            {
                Monitor.Exit(conch);
            }
        }
        static void MethodB3()
        {
            try
            {
                Monitor.TryEnter(conch, TimeSpan.FromSeconds(5));
                for (int i = 0; i < 5; i++)
                {
                    Thread.Sleep(r.Next(1000));
                    Message3 += "B";
                    Console.Write(".");
                }
            }
            finally
            {
                Monitor.Exit(conch);
            }
        }
        static void TestMethod3()
        {
            Stopwatch watch = Stopwatch.StartNew();
            Task a = Task.Factory.StartNew(MethodA3);
            Task b = Task.Factory.StartNew(MethodB3);

            Task.WaitAll(new Task[] { a, b });
            Console.WriteLine($"Message3={Message3}");
            Console.WriteLine($"{watch.ElapsedMilliseconds:#,##0}");
        }
        #endregion

        #region P394 Piranha CMS
        /*
         * Source：https://github.com/PiranhaCMS
         * 文档展示工具：https://github.com/tidyui/statica
         */
        #endregion
    }
}
